<?php

final class Config
{
    static protected $params = array();
    static protected $config_file;
    static protected $config_file_rel_path = 'config.php';

    /**
     * Полезные PHP-константы.
     * PHP_EOL
     * PHP_OS
     * PHP_VERSION
     */

      
    /**
     * Коментарий: Первый вызов осуществляется в движке 
     * в виде: Config::set(debug_backtrace());
     * 
     * @param $name
     * @return unknown_type
     */
    static function set($name)
    {
        static $calls = 0;++$calls;
        /**
         * Первый вызов идёт для указания базовой директории приложения.
         */
        if ($calls == 1) {
            self::setAppPath($name);
            return;
        }

        $value = (func_num_args() > 1) ? func_get_arg(1) : null;
        if (empty(self::$config_file)) {
            throw new ArchException("Function ".__CLASS__."::".__FUNCTION__."() accessible only from application config file.");
        }

        $stack =& debug_backtrace();
        $file = isset($stack[0]['file']) ? $stack[0]['file'] : null;
        if ($file !== self::$config_file) {
            throw new ArchException("Function ".__CLASS__."::".__FUNCTION__."() accessible only from application config file.");
        }

        if (! is_string($name)) {
            throw new ArgException("Invalid config variable name “{$name}”.");
        }

        switch ($name) {

        case "script_encoding":
            self::$params[$name] = $value;
            break;

        case "output_encoding":
            self::$params[$name] = $value;
            break;

        case "web_root_path":
            if (file_exists($value) && is_dir($value)) {
                $ds = DIRECTORY_SEPARATOR;
                $value = str_replace('/', $ds, str_replace('\\', $ds, $value));
                $value = strrpos($value, $ds) !== (strlen($value) - strlen($ds)) ? $value . $ds : $value;
                self::$params[$name] = $value;
            } else {
                throw new ArgException("Invalid argument for “{$name}” config parameter: “{$value}”.");
            }
            break;

        case "views_path":
            if (file_exists($value) && is_dir($value)) {
                $ds = DIRECTORY_SEPARATOR;
                $value = str_replace('/', $ds, str_replace('\\', $ds, $value));
                $value = strrpos($value, $ds) !== (strlen($value) - strlen($ds)) ? $value . $ds : $value;
                self::$params[$name] = $value;
            } else {
                throw new ArgException("Invalid argument for “{$name}” config parameter: “{$value}”.");
            }
            break;

        case "views_ext":
            if (is_string($value)) {
                self::$params[$name] = $value;
            } else {
                throw new ArgException("Invalid argument for “{$name}” config parameter: “{$value}”.");
            }
            break;

        case "text_compress":
            if (is_bool($value)) {
                self::$params[$name] = $value;
            } else {
                throw new ArgException("Invalid argument for “{$name}” config parameter.");
            }
            break;

        default:
            self::$params[$name] = $value;
        }
    }

    static function get($name)
    {
        if (! is_string($name)) {
            throw new ArgException();
        }
        if (isset(self::$params[$name])) {
            return self::$params[$name];
        } else {
            /**
             * Устанавливаем значения по-умолчанию.
             */
            switch ($name) {

            case "script_encoding":
                self::$params[$name] = "ISO-8859-1";
                return self::$params[$name];

            case "output_encoding":
                self::$params[$name] = ini_get("default_charset") ? ini_get("default_charset") : "ISO-8859-1";
                return self::$params[$name];

            case "web_root_path":
                $tmp = null;
                if (! empty($_SERVER['DOCUMENT_ROOT'])) {
                    $ds = DIRECTORY_SEPARATOR;
                    $tmp = str_replace('/', $ds, str_replace('\\', $ds, $_SERVER['DOCUMENT_ROOT']));
                    $tmp = strrpos($tmp, $ds) !== (strlen($tmp) - strlen($ds)) ? $tmp . $ds : $tmp;
                }
                self::$params[$name] = $tmp;
                return self::$params[$name];

            case "text_compress":
                self::$params[$name] = true;
                return self::$params[$name];

            case "app_path":
                return self::$params[$name];

            case "init_script":
                return self::$params[$name];

            case "views_path":
                return self::get("app_path");

            case "views_ext":
                return ".php";

            default:
                return null; // Или исключение?
            }
        }
    }

    static protected function setAppPath($debug_backtrace)
    {
        if (! isset($debug_backtrace[0]["file"])) {
            throw new ArchException("You must include initialization file from application root directory.");
        }
        $init_file = $debug_backtrace[0]["file"];
        $init_dir = dirname($init_file);
        if (! (file_exists($init_dir) && is_readable($init_dir))) {
            throw new ArchException("You must include initialization file from application root directory.");
        }
        self::$params["init_script"] = $init_file;

        $ds = DIRECTORY_SEPARATOR;
        $value = str_replace('/', $ds, str_replace('\\', $ds, $init_dir));
        $value = strrpos($value, $ds) !== (strlen($value) - strlen($ds)) ? $value . $ds : $value;
        if (! (file_exists($value) && is_dir($value))) {
            throw new ArchException("You must include initialization file from application root directory.");
        }
        self::$params["app_path"] = $value;

        $config_file = Config::get("app_path").self::$config_file_rel_path;
        if (file_exists($config_file) && is_readable($config_file)) {
            self::$config_file = $config_file;
            require_once $config_file;
        }
    }

    private function __construct() {}
}

?>